﻿using System;
using System.IO;
using System.Security;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using System.Drawing;

namespace SPALM
{
  // This logger will derive from the Microsoft.Build.Utilities.Logger class,
  // which provides it with getters and setters for Verbosity and Parameters,
  // and a default empty Shutdown() implementation.
  public class UILogger : Logger
  {
    /// <summary>
    /// Initialize is guaranteed to be called by MSBuild at the start of the           
    /// build
    /// before any events are raised.
    /// </summary>
    public override void Initialize(IEventSource eventSource)
    {
      // The name of the log file should be passed as the first item in the
      // "parameters" specification in the /logger switch.  It is required
      // to pass a log file to this logger. Other loggers may have zero or more than 
      // one parameters.

      // For brevity, we'll only register for certain event types. Loggers //can also
      // register to handle TargetStarted/Finished and other events.
      eventSource.ProjectStarted += new
         ProjectStartedEventHandler(eventSource_ProjectStarted);
      eventSource.TaskStarted += new
         TaskStartedEventHandler(eventSource_TaskStarted);
      eventSource.MessageRaised += new
         BuildMessageEventHandler(eventSource_MessageRaised);
      eventSource.WarningRaised += new
         BuildWarningEventHandler(eventSource_WarningRaised);
      eventSource.ErrorRaised += new
         BuildErrorEventHandler(eventSource_ErrorRaised);
      eventSource.ProjectFinished += new
         ProjectFinishedEventHandler(eventSource_ProjectFinished);
      eventSource.StatusEventRaised += new BuildStatusEventHandler(eventSource_StatusEventRaised);
    }

    void eventSource_StatusEventRaised(object sender, BuildStatusEventArgs e)
    {
      WriteLineWithSenderAndMessage("Status:", e);
    }

    void eventSource_BuildFinished(object sender, BuildFinishedEventArgs e)
    {

      WriteLineWithSenderAndMessage("BuildFinished:", e);
    }

    void eventSource_ErrorRaised(object sender, BuildErrorEventArgs e)
    {
      Console.ForegroundColor = ConsoleColor.Red;

      // BuildErrorEventArgs adds LineNumber, ColumnNumber, 
      // File, among other parameters
      string line = String.Format("Error: ",
         e.File, e.LineNumber, e.ColumnNumber);
      WriteLineWithSenderAndMessage(line, e);

      Console.ForegroundColor = ConsoleColor.White;
    }

    void eventSource_WarningRaised(object sender, BuildWarningEventArgs e)
    {
      Console.ForegroundColor = ConsoleColor.Yellow;

      // BuildWarningEventArgs adds LineNumber, ColumnNumber, 
      // File, among other parameters
      string line = String.Format("Warning: ",
         e.File, e.LineNumber, e.ColumnNumber);
      WriteLineWithSenderAndMessage(line, e);

      Console.ForegroundColor = ConsoleColor.White;
    }

    void eventSource_MessageRaised(object sender, BuildMessageEventArgs e)
    {
      // BuildMessageEventArgs adds Importance to BuildEventArgs
      // Let's take account of the verbosity setting we've been 
      //passed in deciding whether to log the message
      if ((e.Importance == MessageImportance.High &&
             IsVerbosityAtLeast(LoggerVerbosity.Minimal))
         || (e.Importance == MessageImportance.Normal &&
             IsVerbosityAtLeast(LoggerVerbosity.Normal))
         || (e.Importance == MessageImportance.Low &&
             IsVerbosityAtLeast(LoggerVerbosity.Detailed))
            )
      {

        if (e.Importance == MessageImportance.High)
        {
          Console.ForegroundColor = ConsoleColor.White;
          indent = 0;
        }
        else if (e.Importance == MessageImportance.Normal)
        {
          Console.ForegroundColor = ConsoleColor.Gray;
          indent = 2;
        }
        else if (e.Importance == MessageImportance.Low)
        {
          Console.ForegroundColor = ConsoleColor.DarkGray;
          indent = 4;
        }

        if (e.SenderName.Equals("Exec", StringComparison.InvariantCultureIgnoreCase))
        {
          Console.ForegroundColor = ConsoleColor.DarkGray;
        }

        WriteLineWithSenderAndMessage(String.Empty, e);

        indent = 0;
        Console.ForegroundColor = ConsoleColor.White;

      }
    }

    void eventSource_TaskStarted(object sender, TaskStartedEventArgs e)
    {
      // TaskStartedEventArgs adds ProjectFile, TaskFile, TaskName
      // To keep this log clean, this logger will ignore these events.
    }

    void eventSource_ProjectStarted(object sender, ProjectStartedEventArgs e)
    {
      // ProjectStartedEventArgs adds ProjectFile, TargetNames
      // Just the regular message string is good enough here, so just //display that.
      //WriteLine(String.Empty, e);
      indent++;
    }

    void eventSource_ProjectFinished(object sender, ProjectFinishedEventArgs e)
    {

      // The regular message string is good enough here too.
      indent--;
      //WriteLine(String.Empty, e);
    }

    /// <summary>
    /// Write a line to the log, adding the SenderName and Message
    /// (these parameters are on all MSBuild event argument objects)
    /// </summary>
    private void WriteLineWithSenderAndMessage(string line, BuildEventArgs e)
    {
      if (0 == String.Compare(e.SenderName, "MSBuild", true /*ignore case*/))
      {
        // Well, if the sender name is MSBuild, let's leave it out for prettiness
        //WriteLine(line, e);
      }
      else
      {
        WriteLine(line, e);
      }
    }

    /// <summary>
    /// Just write a line to the log
    /// </summary>
    private void WriteLine(string line, BuildEventArgs e)
    {
      for (int i = indent; i > 0; i--)
      {
        Console.Write(" ");
      }
      Console.WriteLine(e.Message);
    }

    /// <summary>
    /// Shutdown() is guaranteed to be called by MSBuild at the end of  
    ///the build, after all 
    /// events have been raised.
    /// </summary>
    public override void Shutdown()
    {
      // Done logging, let go of the file
      //streamWriter.Close();
    }

    private int indent;
  }
}

